Skip to content

feat(sandbox): opt-in to AF_NETLINK socket creation via env var#1006

Closed
alessandro-festa wants to merge 1 commit into
NVIDIA:mainfrom
alessandro-festa:feat/seccomp-allow-netlink-enumerate
Closed

feat(sandbox): opt-in to AF_NETLINK socket creation via env var#1006
alessandro-festa wants to merge 1 commit into
NVIDIA:mainfrom
alessandro-festa:feat/seccomp-allow-netlink-enumerate

Conversation

@alessandro-festa
Copy link
Copy Markdown

Summary

Adds OPENSHELL_ALLOW_NETLINK_ENUMERATE (default off) so deployments that run Node.js / Go / Python tooling inside the sandbox can let it call getifaddrs(3). Today this fails with EPERM under the supervisor's seccomp filter and surfaces as opaque "Unknown system error 1" stack traces from libuv (Node's os.networkInterfaces()), Go's net.Interfaces(), Python's socket.if_nameindex(), etc.

The default behavior is unchanged: AF_NETLINK stays in the seccomp denylist. Setting the env var to 1 / true / yes drops exactly that one rule. AF_PACKET, AF_BLUETOOTH, and AF_VSOCK remain blocked unconditionally.

Related Issue

No upstream issue filed yet — happy to file one and link if preferred. Hit while building a sandboxed Node.js agent (the openclaw CLI from OpenShell-Community/sandboxes/openclaw) inside an OpenShell sandbox: pickPrimaryLanIPv4 calls os.networkInterfaces()uv_interface_addressesgetifaddrs(3)socket(AF_NETLINK, ...)EPERM, which the agent doesn't tolerate.

Changes

  • crates/openshell-sandbox/src/sandbox/linux/seccomp.rs:
    • apply() reads OPENSHELL_ALLOW_NETLINK_ENUMERATE from env (case-insensitive 1/true/yes)
    • build_filter/build_filter_rules take a new allow_netlink: bool parameter
    • When allow_netlink is true, AF_NETLINK is left out of the socket-domain denylist; otherwise behavior is identical to today
  • Tests:
    • existing build_filter_*_compiles tests updated to the new signature
    • build_filter_netlink_allowed_compiles covers the opt-in path
    • netlink_blocked_by_default verifies the default-deny still installs a SYS_socket rule
    • netlink_allowed_drops_one_socket_rule verifies the opt-in drops exactly one socket-domain rule

Caveats

This is a coarse opt-in: once the AF_NETLINK socket is created the process can issue any RTM_* message (route table, neighbor table, etc.). A finer-grained policy that filters at the netlink message level would need an LSM/eBPF hook and is out of scope here. The use case it unblocks (interface enumeration for self-presence detection) is common enough in real-world Node/Go/Python codebases that an explicit opt-in seems worth the trade-off.

If you'd prefer this as a per-policy field (SandboxPolicy.network.allow_netlink) instead of an env var, happy to refactor — went with env var for the smallest diff and to avoid a proto bump.

Testing

  • cargo build -p openshell-sandbox (host: macOS arm64) clean
  • cargo build -p openshell-sandbox --release via Dockerfile.images supervisor target — multi-arch (linux/amd64 + linux/arm64) succeeds
  • New unit tests cover both paths and the rule-count delta
  • Tested against a sandboxed Node.js workload — os.networkInterfaces() succeeds with OPENSHELL_ALLOW_NETLINK_ENUMERATE=true, fails with EPERM otherwise (will validate in the smoke test today and update this checkbox)

Checklist

  • Conventional Commits message
  • Tests added
  • No upstream-only files (CLAUDE.md / AGENTS.md / README.md) modified
  • No secrets in diff

Adds OPENSHELL_ALLOW_NETLINK_ENUMERATE (default off) so deployments that
ship Node.js / Go / Python tooling inside the sandbox can let it call
getifaddrs(3) — Node's `os.networkInterfaces()`, Go's `net.Interfaces()`,
Python's `socket.if_nameindex()` all open AF_NETLINK sockets and currently
fail with EPERM under the supervisor's seccomp filter, surfacing as
opaque "Unknown system error 1" stack traces from libuv and friends.

The default behavior is unchanged: AF_NETLINK socket creation stays in
the seccomp denylist. Setting the env var to "1" / "true" / "yes" drops
exactly that one rule. AF_PACKET, AF_BLUETOOTH and AF_VSOCK remain
blocked unconditionally.

Once the AF_NETLINK socket is created the process can issue any RTM_*
netlink message; this is a coarse opt-in. A finer-grained policy that
filters at the netlink message level would need an LSM/eBPF hook and is
out of scope.

Tests:
- existing build_filter compile tests updated to the new (allow_inet,
  allow_netlink) signature
- new tests cover the default-deny path, the opt-in path, and the
  rule-count delta between them
@alessandro-festa alessandro-festa requested a review from a team as a code owner April 28, 2026 14:32
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 28, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions
Copy link
Copy Markdown

Thank you for your interest in contributing to OpenShell, @alessandro-festa.

This project uses a vouch system for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer.

To get vouched:

  1. Open a Vouch Request discussion.
  2. Describe what you want to change and why.
  3. Write in your own words — do not have an AI generate the request.
  4. A maintainer will comment /vouch if approved.
  5. Once vouched, open a new PR (preferred) or reopen this one after a few minutes.

See CONTRIBUTING.md for details.

@github-actions github-actions Bot closed this Apr 28, 2026
@github-actions
Copy link
Copy Markdown

Thank you for your submission! We ask that you sign our Developer Certificate of Origin before we can accept your contribution. You can sign the DCO by adding a comment below using this text:


I have read the DCO document and I hereby sign the DCO.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the DCO Assistant Lite bot.

@alessandro-festa
Copy link
Copy Markdown
Author

I have read the DCO document and I hereby sign the DCO.

@EmilienM
Copy link
Copy Markdown

EmilienM commented May 5, 2026

can we please re-open it?

@cgwalters
Copy link
Copy Markdown
Contributor

My opinion on this is that this seccomp rule is not providing value; historical kernel vulnerabilities in this space were more tied to user namespaces and netlink.

But that said, I think unprivileged netlink is pretty heavily fuzzed nowadays too.

So I'd say just allow by default.

(Also I am of the opinion that more generally the additional seccomp/landlock stuff on top of the default container runtime security should all be opt-in, but that's a much bigger discussion)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants